<script setup lang="ts">
import { nextTick, reactive, ref, unref, watch } from 'vue'
import {
  ArrowDown,
  SetUp,
  Avatar,
  BottomLeft,
  Close,
  EditPen,
  Refresh,
  Stamp,
  Share
} from '@element-plus/icons-vue'
import { useWfApi } from '@/api/wf'
import type {
  BaseFormRow,
  BusinessUIFormType,
  DicType,
  IsWorkFlowDesign,
  RuningDetail,
  WorkFlowDesignInfoRunning,
  WorkflowDesignRow
} from '@/types/custom'
import type { Fn } from '@vueuse/core'
import { ElMessage, ElMessageBox } from 'element-plus'
import { themeConfig } from '@/storage'
import emitter from '@/utils/mitt'
import { getNotEmpty } from '@/utils/custom'
import { useAppState } from '@/stores/appState'

import CustomTagView from '@/components/CustomTagView.vue'
import TemplateForm from '@/views/components/form/TemplateForm.vue'
import AppDetailsChange from '@/components/custom/AppDetailsChange.vue'
import NeedViewTimeline from '@/views/system/flow/component/NeedViewTimeline.vue'

interface RuleForm {
  approvalType: number
  remark: string
  approvalUsersId: string[]
  sendMsg: boolean
  sendSms: boolean
  multApp: boolean
  runingId: string
}

const {
  GetRunningTitles,
  GetWorkFlowDesignInfo,
  WorkFlowRuingApproval,
  WorkFlowRuingDelegate,
  WorkFlowRuingDel,
  WorkFlowRuingStart
} = useWfApi()

const { mobile } = useAppState()

const emit = defineEmits(['fetch'])

// 是否编辑
const isSave = ref(false)
// 表单实例
const formRef = ref<InstanceType<typeof TemplateForm>>()
// 流程状态修改组件
const wfStatusRef = ref<InstanceType<typeof AppDetailsChange>>()
// 时间线
const timeRef = ref<InstanceType<typeof NeedViewTimeline>>()
// 加载中
const loading = ref(false)
// 弹窗
const dialogVisible = ref(false)
// 所有流程 id
const items = ref<SelectOptionType[]>([])
// 流程实例rowId
const instanceId = ref('')
// 可编辑列
const can_edit_items = ref<string[]>([])
// 表单
const uiForm = ref<BusinessUIFormType | undefined>()
// 表单字典
const dicTable = ref<DicType[]>([])
// 流程图
const design = ref<WorkflowDesignRow>({ id: '', name: '', nodes: [], edges: [] })
// 时间线
const activities = ref<RuningDetail[]>([])
// 审批权限
const wfRunning = ref<IsWorkFlowDesign>({
  can_approval: false,
  can_submit: false,
  can_un_approval: false,
  can_un_submit: false,
  can_set_status: false
})
// 表单
const ruleForm = reactive<RuleForm>({
  approvalType: 0,
  remark: '',
  approvalUsersId: [],
  sendMsg: false,
  sendSms: false,
  multApp: false,
  runingId: ''
})

// 审批名称
const approvalTypeNames: TypedAny<string> = {
  0: '审批',
  1: '回退',
  2: '回退到开始',
  3: '不同意',
  99: '委派',
  98: '撤回提交'
}

const open = async (option: BaseFormRow) => {
  const ids = option.list
  const running_id = option.running_id
  if (ids?.length) {
    ruleForm.runingId = running_id || ids[0]
    const { data } = await GetRunningTitles<{ [key: string]: string }[]>({ rows: ids })
    const list: SelectOptionType[] = []
    for (const key in data) {
      list.push({
        label: String(data[key]),
        value: key
      })
    }

    list.sort((a) => {
      if (a.value === running_id) {
        return -1
      } else {
        return 0
      }
    })

    items.value = list

    dialogVisible.value = true
  } else {
    ElMessage.warning('未传入流程ID')
  }
}

/**
 * 生成时间线
 * @param running
 */
const onActivities = (running: WorkFlowDesignInfoRunning) => {
  if (running.node) {
    running.details.push({
      id: '',
      nodeId: running.runing.nodeId,
      nodeLabel: `待 ${running.node.label}`,
      nodeName: `待 ${running.node.label}`,
      approvalUser: running.runing.approvalUsers,
      approvalTypeString: running.runing.statusString,
      nodeType: running.node.nodeType,
      modifiedOnString: ''
    })
  }

  const list: RuningDetail[] = []
  running.details.forEach((v) => {
    // const node = running.design.nodes.find((f) => f.id === v.nodeId)
    // v.label = v.label ? v.label : node?.label || ''
    if (v.nodeId === 'start') {
      v.props = {
        type: 'success',
        hollow: true
      }
    } else if (v.nodeId === 'end') {
      v.props = {
        type: 'danger',
        hollow: false
      }
    } else if (!v.id) {
      v.props = {
        type: 'primary',
        hollow: false
      }
    } else {
      const approvalType: TypedAny = {
        '2': 'warning',
        '3': 'danger'
      }
      v.props = {
        type: getNotEmpty(approvalType, [String(v.approvalType)], 'primary'),
        hollow: false
      }
    }
    list.push(v)
  })
  list.reverse()
  activities.value = list

  return list
}

const onFetch = async () => {
  try {
    loading.value = true
    const { data } = await GetWorkFlowDesignInfo(ruleForm.runingId)
    const running = data.runing
    wfRunning.value = data.wfRuning
    instanceId.value = running.runing.instanceId
    can_edit_items.value = data.can_edit_items || []
    dicTable.value = data.dic_table || []
    if (data.ui_form) uiForm.value = data.ui_form

    isSave.value = !!data.can_edit_items.length

    const list = onActivities(running)

    if (running.design) {
      const nodes = running.design.nodes || []
      const edges = running.design.edges || []

      const start = running.design.nodes.find((f) => f.id === 'start')
      if (start) {
        const starts = [start]
        const results: WorkflowDesignNode[][] = [starts]
        nextNodes(nodes, edges, starts, results)
        let end = false
        results.forEach((nodes) => {
          nodes.forEach((node) => {
            if (!end) {
              node.disabled = !list.some((s) => s.nodeId === node.id)
              if (node.disabled && node.nodeId === 'end') {
                end = true
              }
            }
          })
        })
        // stamps.value = results
      }
      design.value = running.design
      isSave.value = !!data.can_edit_items.length
    }

    await nextTick()
    // 查询表单
    await onFetchForm()
    // 延迟一秒
    await new Promise((resolve) => setTimeout(resolve, 500))
    // 结束加载
    loading.value = false
  } catch (e) {
    // 结束加载
    loading.value = false
  }
}

/**
 * 整个流程
 * @param nodes
 * @param edges
 * @param starts
 * @param results
 */
const nextNodes = (
  nodes: WorkflowDesignNode[],
  edges: WorkflowDesignEdge[],
  starts: WorkflowDesignNode[],
  results: any[]
) => {
  const items: WorkflowDesignNode[] = []
  starts.forEach((n) => {
    const ls = getNodes(nodes, edges, n)
    items.push(...ls)
  })
  if (items.length) {
    results.push(items)
    nextNodes(
      nodes,
      edges,
      items.filter((node) => {
        const lines = edges.filter((f) => f.sourceId === node.id)
        return !items.some((i) => lines.some((s) => s.targetId === i.id))
      }),
      results
    )
  }
  return results
}

/**
 * 获取节点
 * @param nodes
 * @param edges
 * @param node
 */
const getNodes = (
  nodes: WorkflowDesignNode[],
  edges: WorkflowDesignEdge[],
  node: WorkflowDesignNode
) => {
  const lines = edges.filter((f) => f.sourceId === node.id)
  const results: WorkflowDesignNode[] = []
  lines.forEach((line) => {
    const dots = nodes.filter((f) => f.id === line.targetId)
    results.push(...dots)
  })
  return results
}

/**
 * 保存
 */
const onSave = () => {
  ElMessageBox.confirm(`确认要保存修改吗？`, '提示框', {
    confirmButtonText: '确认保存',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(() => {
      loading.value = true
      formRef.value
        ?.submitForm()
        .then(({ data }: any) => {
          if (data && data.forms && data.forms.length) {
            // 把数据广播给表单
            emitter.emit('onUpdateParent', data)
          }
          onFetch()
          ElMessage.success('保存成功')
        })
        .catch(() => {
          ElMessage.warning('请先完善表中的必填项目')
        })
        .finally(() => (loading.value = false))
    })
    .catch(() => {})
}

/**
 * 刷新表单
 */
const onFetchForm = async () => {
  const $form = unref(formRef)
  if ($form) await $form.onFetch()
}

/**
 * 获取下一步是否需要选择用户
 */
const onOpenRuingNext = (params?: object): Promise<string | undefined> => {
  return new Promise((callback) => {
    emitter.emit('onOpenRuingNext', { params, callback })
  })
}

/**
 * 撤回工作流
 */
const onCanUnSubmit = () => {
  ElMessageBox.confirm(`确认要撤回吗？`, '提示框', {
    confirmButtonText: '确认撤回',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(() => {
      WorkFlowRuingDel(ruleForm.runingId).then(() => {
        onNextStep()
      })
    })
    .catch(() => {})
}
/**
 * 打开选择用户
 */
const onOpenSelectUser = (): Promise<string | undefined> => {
  return new Promise((callback) => {
    emitter.emit('onOpenSelectUser', { callback })
  })
}

/**
 * 弹窗回调
 */
interface MessageBoxInstance {
  done: Fn
  instance: {
    confirmButtonLoading: boolean
    confirmButtonText: string
  }
}

/**
 * 填写审批意见
 */
const openMessageBox = (text: string): Promise<MessageBoxInstance> => {
  return new Promise((resolve) => {
    if (ruleForm.remark) {
      resolve({
        done: () => {},
        instance: { confirmButtonLoading: false, confirmButtonText: text }
      })
    } else {
      ElMessageBox.prompt(`请确认${text}意见`, `${text}意见`, {
        showCancelButton: true,
        confirmButtonText: `确认${text}`,
        cancelButtonText: '取消',
        type: 'warning',
        inputErrorMessage: ``,
        autofocus: false,
        inputValue: ruleForm.approvalType === 0 ? 'OK' : '',
        inputValidator: (value) => {
          return (value || '').trim() ? true : `请输入 ${text} 意见`
        },
        beforeClose: (action, instance, done) => {
          if (action === 'confirm') {
            instance.confirmButtonLoading = true
            instance.confirmButtonText = `${text}中...`
            ruleForm.remark = instance.inputValue
            resolve({ instance, done })
          } else {
            done()
          }
        }
      })
    }
  })
}

/**
 * 提交
 */
const submitForm = async (approvalType: 0 | 1 | 2 | 3 | 98 | 99) => {
  ruleForm.approvalType = approvalType
  if (approvalType === 98) {
    return onCanUnSubmit()
  } else if (approvalType === 99) {
    const userId = await onOpenSelectUser()
    if (userId === 'close') return
    else ruleForm.approvalUsersId = userId ? [userId] : []
  } else if ([0, 99].includes(approvalType)) {
    const userId = await onOpenRuingNext({
      instanceName: design.value.instanceName,
      instanceId: instanceId.value,
      flag: design.value.flag
    })
    if (userId === 'close') return
    else ruleForm.approvalUsersId = userId ? [userId] : []
  }

  // 呼出意见填写
  const text = approvalTypeNames[ruleForm.approvalType]
  const { done, instance } = await openMessageBox(text)
  try {
    if (approvalType === 99) {
      await onDelegate()
    } else {
      await onSubmit()
    }
    await onFetch()
    ElMessage.success(`${text} 成功`)
  } catch (e) {
    console.log('审批失败')
  }
  instance.confirmButtonLoading = false
  instance.confirmButtonText = text
  done()
}

/**
 * 委派
 */
const onDelegate = async () => {
  return WorkFlowRuingDelegate({
    runingId: ruleForm.runingId,
    approvalUserId: ruleForm.approvalUsersId.length ? ruleForm.approvalUsersId[0] : '',
    remark: ruleForm.remark,
    sendMsg: false,
    sendSms: false
  }).then(() => {
    onNextStep()
  })
}

/**
 * 提交
 */
const onSubmit = async () => {
  return WorkFlowRuingApproval(ruleForm).then((res) => {
    onNextStep()
    return res
  })
}

const onIconClick = ({ index }: { index: number }) => {
  items.value.splice(index, 1)
  if (items.value.every((s) => s.value !== ruleForm.runingId)) {
    if (items.value.length) ruleForm.runingId = String(items.value[0].value)
    else {
      dialogVisible.value = false
    }
  }
}

let isApp = false

/**
 * 下一步，检测是否需要关闭弹窗
 */
const onNextStep = () => {
  ruleForm.remark = ''
  isApp = true
  if (items.value.length > 1) {
    const index = items.value.findIndex((f) => f.value === ruleForm.runingId)
    if (index >= 0) onIconClick({ index })
  } else {
    dialogVisible.value = false
  }
}

const openStatusChange = () => {
  wfStatusRef.value?.open(ruleForm.runingId)
}

/**
 * 表格和弹窗都刷新
 */
const onRefreshAll = () => {
  onFetch()
  emit('fetch')
}

/**
 * 关闭弹窗刷新表格刷新
 */
const onCloseRefreshTable = () => {
  emit('fetch')
  dialogVisible.value = false
}

const onReset = () => {
  isApp = false
  uiForm.value = undefined
  ruleForm.runingId = ''
  for (const key in wfRunning.value) {
    // @ts-ignore
    wfRunning.value[key] = false
  }
}

/**
 * 提交工作流
 * @param userId
 */
const onCanSubmit = (userId?: string) => {
  if (userId !== 'close') {
    WorkFlowRuingStart({
      instanceName: design.value.instanceName,
      flag: design.value.flag,
      remark: '',
      approvalUsersId: userId ? [userId] : [],
      sendMsg: false,
      sendSms: false,
      multApp: false,
      instanceId: instanceId.value
    }).then(() => {
      onFetch()
      isApp = true
      ElMessage.success('提交成功')
    })
  }
}

/**
 * 工作流提交
 */
const onRuingNext = () => {
  emitter.emit('onOpenRuingNext', {
    params: {
      instanceName: design.value.instanceName,
      instanceId: instanceId.value,
      flag: design.value.flag
    },
    callback: onCanSubmit
  })
}

const openWorkflow = () => {
  if (design.value?.id) emitter.emit('onOpenWorkflow', unref(design))
}

watch(dialogVisible, (visible) => {
  if (!visible) {
    if (isApp) {
      isApp = false
      emit('fetch')
      emitter.emit('onUpdateMsgDot')
    }
    setTimeout(onReset, 300)
  }
})

watch(
  () => ruleForm.runingId,
  (id) => {
    if (id) {
      // 可编辑和详情使用不同方式渲染，提升性能
      if (can_edit_items.value.length) {
        onFetch()
      } else {
        uiForm.value = undefined
        nextTick(onFetch)
      }
    }
  }
)

defineExpose({ open })
</script>

<template>
  <el-dialog
    v-model="dialogVisible"
    width="90%"
    class="custom-dialog h100"
    append-to-body
    destroy-on-close
  >
    <template #header>
      <div class="flex align-center flex-warp pr10" style="gap: 5px 0">
        <CustomTagView
          v-model="ruleForm.runingId"
          :items="items"
          @icon-click="onIconClick"
          :loading="loading"
          style="min-width: 300px"
        />
        <el-space :size="[5, 5]">
          <el-button :icon="Refresh" @click="onFetch()" :loading="loading">刷新</el-button>
          <el-button @click="openWorkflow" :icon="Share" v-if="!mobile">流程图</el-button>
          <el-button type="danger" v-if="wfRunning.can_set_status" @click="openStatusChange">
            修改流程状态
          </el-button>
          <el-button
            v-if="isSave"
            :icon="EditPen"
            type="primary"
            @click="onSave"
            :loading="loading"
          >
            保存
          </el-button>
        </el-space>
      </div>
    </template>
    <div
      class="custom-dialog-content app-detail-loading relative"
      v-loading="loading"
      element-loading-text="奋力加载中..."
      :element-loading-background="themeConfig.isIsDark ? '#000000' : '#ffffff'"
    >
      <NeedViewTimeline
        ref="timeRef"
        :activities="activities"
      />
      <TemplateForm
        v-if="uiForm"
        ref="formRef"
        :is-form="!!can_edit_items.length"
        v-model="instanceId"
        :ui-form="uiForm"
        :dic-table="dicTable"
        :can_edit_items="can_edit_items"
      />
      <!--      :ready="onFormReady"-->
      <div style="height: 20px; width: 100%"></div>
    </div>
    <template #footer>
      <div class="custom-dialog-footer">
        <el-button class="mb5" :icon="Close" @click="dialogVisible = false">关闭</el-button>
        <el-input
          v-if="wfRunning.can_approval"
          style="width: 290px"
          v-model="ruleForm.remark"
          placeholder="请输入意见"
          type="text"
          class="ml5 mb5"
        />
        <el-button
          v-if="wfRunning.can_approval"
          type="primary"
          @click="submitForm(0)"
          :loading="loading"
          :icon="Stamp"
          class="mb5 ml5 px20"
        >
          同意审批
        </el-button>
        <el-button
          v-if="wfRunning.can_submit"
          type="warning"
          @click="onRuingNext"
          :loading="loading"
          :icon="SetUp"
          class="mb5 ml5 px20"
        >
          重新提交
        </el-button>
        <el-dropdown @command="submitForm" v-if="wfRunning.can_un_submit || wfRunning.can_approval">
          <el-button :icon="ArrowDown" :loading="loading" class="mb5 ml5">更多操作</el-button>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item :command="98" v-if="wfRunning.can_un_submit">
                <el-button type="danger" style="width: 100%" :icon="BottomLeft">撤回提交</el-button>
              </el-dropdown-item>
              <el-dropdown-item :command="99" v-if="wfRunning.can_approval">
                <el-button type="success" style="width: 100%" :icon="Avatar">委派</el-button>
              </el-dropdown-item>
              <!--                <el-dropdown-item :command="0">-->
              <!--                  <el-button type="primary" style="width: 100%" :icon="Stamp">同意审批</el-button>-->
              <!--                </el-dropdown-item>-->
              <el-dropdown-item :command="1" v-if="wfRunning.can_approval">
                <el-button type="warning" style="width: 100%" :icon="BottomLeft"
                  >回退上一步
                </el-button>
              </el-dropdown-item>
              <!--              <el-dropdown-item :command="2" v-if="wfRunning.can_approval">-->
              <!--                <el-button type="warning" style="width: 100%" :icon="ArrowLeft"-->
              <!--                  >回退到开始-->
              <!--                </el-button>-->
              <!--              </el-dropdown-item>-->
              <el-dropdown-item :command="3" v-if="wfRunning.can_approval">
                <el-button type="danger" style="width: 100%" :icon="Close">不同意</el-button>
              </el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </div>
    </template>
  </el-dialog>
  <AppDetailsChange ref="wfStatusRef" @fetch="onRefreshAll" @close="onCloseRefreshTable" />
</template>
<style lang="scss">
.app-detail-loading .el-loading-spinner {
  top: 200px !important;
  margin-top: 0 !important;
}
</style>
